# -*- coding: utf-8 -*-
#
# dumper.py
#
#
# PyEMOF: An EMOF support for Python
#
# Copyright (C) 2004, 2007 Raphael Marvie 
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# http://www.fsf.org/licensing/licenses/gpl.html
#
# Author contact: raphael.marvie@lifl.fr
#
# Modified and adapted to conform with ECORE 2.0 by brenomachado@gmail.com



from xml.dom import minidom

import emof.core

class DumpElement (object):
    def __init__ (self, doc):
        super(DumpElement, self).__init__()
        self._doc = doc
    def process(self, obj, elt):
        elt.setAttributeNS('xmi', 'xmi:id', obj._xmi_id)
    def __call__(self, obj, nodename):
        elt = self._doc.createElement(nodename)
        self.process(obj, elt)
        return elt


class Element (DumpElement):

    def __init__(self, doc):
        super(Element, self).__init__(doc)

    def process(self, obj, elt):
        super(Element, self).process(obj, elt)
        if elt.nodeName == 'emof:Element':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Element')
        for o in obj.ownedComment:
            child = self._doc.createElement('ownedComment')
            child.setAttributeNS('xmi', 'xmi:type', ('emof:' + o.__class__.__name__))
            child.setAttributeNS(None, 'idref', o._xmi_id)
            elt.appendChild(child)
        for o in obj.tag:
            child = self._doc.createElement('tag')
            child.setAttributeNS('xmi', 'xmi:type', ('emof:' + o.__class__.__name__))
            child.setAttributeNS(None, 'idref', o._xmi_id)
            elt.appendChild(child)


class Comment (Element):

    def __init__(self, doc):
        super(Comment, self).__init__(doc)

    def process(self, obj, elt):
        super(Comment, self).process(obj, elt)
        if elt.nodeName == 'emof:Comment':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Comment')
        if obj.body:
            elt.setAttributeNS(None, 'body', unicode(obj.body))
        for o in obj.annotatedElement:
            child = self._doc.createElement('annotatedElement')
            child.setAttributeNS('xmi', 'xmi:type', ('emof:' + o.__class__.__name__))
            child.setAttributeNS(None, 'idref', o._xmi_id)
            elt.appendChild(child)

class NamedElement (Element):

    def __init__(self, doc):
        super(NamedElement, self).__init__(doc)

    def process(self, obj, elt):
        super(NamedElement, self).process(obj, elt)
        if elt.nodeName == 'emof:NamedElement':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:NamedElement')
        if obj.name:
            elt.setAttributeNS(None, 'name', unicode(obj.name))


class Tag (Element):

    def __init__(self, doc):
        super(Tag, self).__init__(doc)

    def process(self, obj, elt):
        super(Tag, self).process(obj, elt)
        if elt.nodeName == 'emof:Tag':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Tag')
        if obj.name:
            elt.setAttributeNS(None, 'name', unicode(obj.name))
        if obj.value:
            elt.setAttributeNS(None, 'value', unicode(obj.value))
        for o in obj.element:
            child = self._doc.createElement('element')
            child.setAttributeNS('xmi', 'xmi:type', ('emof:' + o.__class__.__name__))
            child.setAttributeNS(None, 'idref', o._xmi_id)
            elt.appendChild(child)

#OK
class Package (NamedElement):

    def __init__(self, doc):
        super(Package, self).__init__(doc)

    def process(self, obj, elt):
        super(Package, self).process(obj, elt)
        if elt.nodeName == 'emof:Package':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Package')
        if obj.uri:
            elt.setAttributeNS(None, 'uri', unicode(obj.uri))
        for o in obj.nestedPackage:
            clss = dumpers[type(o)]
            child = clss(self._doc)(o, 'nestedPackage')
            elt.appendChild(child)
        #if obj.nestingPackage:
        #    elt.setAttributeNS(None, 'nestingPackage', obj.nestingPackage._xmi_id)
        for o in obj.ownedType:
            clss = dumpers[type(o)]
            child = clss(self._doc)(o, 'ownedType')
            elt.appendChild(child)


class TypedElement (NamedElement):

    def __init__(self, doc):
        super(TypedElement, self).__init__(doc)

    def process(self, obj, elt):
        super(TypedElement, self).process(obj, elt)
        if elt.nodeName == 'emof:TypedElement':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:TypedElement')
        if obj.type:
            elt.setAttributeNS(None, 'type', obj.type._xmi_id)


#OK
class EnumerationLiteral (NamedElement):

    def __init__(self, doc):
        super(EnumerationLiteral, self).__init__(doc)

    def process(self, obj, elt):
        super(EnumerationLiteral, self).process(obj, elt)
        if elt.nodeName == 'emof:EnumerationLiteral':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:EnumerationLiteral')
        #if obj.enumeration:
        #    elt.setAttributeNS(None, 'enumeration', obj.enumeration._xmi_id)


class Type (NamedElement):

    def __init__(self, doc):
        super(Type, self).__init__(doc)

    def process(self, obj, elt):
        super(Type, self).process(obj, elt)
        if elt.nodeName == 'emof:Type':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Type')
        #if obj.package:
        #    elt.setAttributeNS(None, 'package', obj.package._xmi_id)


class MultiplicityElement (TypedElement):

    def __init__(self, doc):
        super(MultiplicityElement, self).__init__(doc)

    def process(self, obj, elt):
        super(MultiplicityElement, self).process(obj, elt)
        if elt.nodeName == 'emof:MultiplicityElement':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:MultiplicityElement')
        if obj.isOrdered:
            elt.setAttributeNS(None, 'isOrdered', unicode(obj.isOrdered))
        if obj.isUnique:
            elt.setAttributeNS(None, 'isUnique', unicode(obj.isUnique))
        if obj.lower:
            elt.setAttributeNS(None, 'lower', unicode(obj.lower))
        if obj.upper:
            elt.setAttributeNS(None, 'upper', unicode(obj.upper))


class DataType (Type):

    def __init__(self, doc):
        super(DataType, self).__init__(doc)

    def process(self, obj, elt):
        super(DataType, self).process(obj, elt)
        if elt.nodeName == 'emof:DataType':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:DataType')


class Class (Type):

    def __init__(self, doc):
        super(Class, self).__init__(doc)

    def process(self, obj, elt):
        super(Class, self).process(obj, elt)
        if elt.nodeName == 'emof:Class':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Class')
        if obj.isAbstract:
            elt.setAttributeNS(None, 'isAbstract', unicode(obj.isAbstract))
        for o in obj.ownedAttribute:
            clss = dumpers[type(o)]
            child = clss(self._doc)(o, 'ownedAttribute')
            elt.appendChild(child)
        for o in obj.ownedOperation:
            clss = dumpers[type(o)]
            child = clss(self._doc)(o, 'ownedOperation')
            elt.appendChild(child)
        for o in obj.superClass:
            x = elt.getAttributeNS(None, 'superClass')
            if x:
                elt.removeAttributeNS(None, 'superClass')
                elt.setAttributeNS(None, 'superClass', (unicode(x) + ' ' + o._xmi_id))
            else:
                elt.setAttributeNS(None, 'superClass', o._xmi_id)
            #child = self._doc.createElement('superClass')
            #child.setAttributeNS('xmi', 'xmi:type', ('emof:' + o.__class__.__name__))
            #child.setAttributeNS(None, 'idref', o._xmi_id)
            ##value = self._doc.createTextNode(o._xmi_id)
            ##child.appendChild(value)
            #elt.appendChild(child)


class Operation (MultiplicityElement):

    def __init__(self, doc):
        super(Operation, self).__init__(doc)

    def process(self, obj, elt):
        super(Operation, self).process(obj, elt)
        if elt.nodeName == 'emof:Operation':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Operation')
        for o in obj.raisedException:
            child = self._doc.createElement('raisedException')
            child.setAttributeNS('xmi', 'xmi:type', ('emof:' + o.__class__.__name__))
            child.setAttributeNS(None, 'idref', o._xmi_id)
            #value = self._doc.createTextNode(o._xmi_id)
            #child.appendChild(value)
            elt.appendChild(child)
        for o in obj.ownedParameter:
            clss = dumpers[type(o)]
            child = clss(self._doc)(o, 'ownedParameter')
            elt.appendChild(child)
        #if obj.class_:
        #    elt.setAttributeNS(None, 'class', obj.class_._xmi_id)


class Parameter (MultiplicityElement):

    def __init__(self, doc):
        super(Parameter, self).__init__(doc)

    def process(self, obj, elt):
        super(Parameter, self).process(obj, elt)
        if elt.nodeName == 'emof:Parameter':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Parameter')
        #if obj.operation:
        #    elt.setAttributeNS(None, 'operation', obj.operation._xmi_id)
        if obj.type:
            elt.setAttributeNS(None, 'type', obj.type._xmi_id)

class Property (MultiplicityElement):

    def __init__(self, doc):
        super(Property, self).__init__(doc)

    def process(self, obj, elt):
        super(Property, self).process(obj, elt)
        if elt.nodeName == 'emof:Property':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Property')
        if obj.isReadOnly:
            elt.setAttributeNS(None, 'isReadOnly', unicode(obj.isReadOnly))
        if obj.default:
            elt.setAttributeNS(None, 'default', unicode(obj.default))
        if obj.isComposite:
            elt.setAttributeNS(None, 'isComposite', unicode(obj.isComposite))
        if obj.isDerived:
            elt.setAttributeNS(None, 'isDerived', unicode(obj.isDerived))
        if obj.isId:
            elt.setAttributeNS(None, 'isId', unicode(obj.isId))
        if obj.opposite:
            elt.setAttributeNS(None, 'opposite', obj.opposite._xmi_id)
        #if obj.class_:
        #    elt.setAttributeNS(None, 'class', obj.class_._xmi_id)
        if obj.type:
            elt.setAttributeNS(None, 'type', obj.type._xmi_id)

#OK
class Enumeration (DataType):

    def __init__(self, doc):
        super(Enumeration, self).__init__(doc)

    def process(self, obj, elt):
        super(Enumeration, self).process(obj, elt)
        if elt.nodeName == 'emof:Enumeration':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:Enumeration')
        for o in obj.ownedLiteral:
            clss = dumpers[type(o)]
            child = clss(self._doc)(o, 'ownedLiteral')
            elt.appendChild(child)

class PrimitiveType (DataType):

    def __init__(self, doc):
        super(PrimitiveType, self).__init__(doc)

    def process(self, obj, elt):
        super(PrimitiveType, self).process(obj, elt)
        if elt.nodeName == 'emof:PrimitiveType':
            try: 
                elt.removeAttributeNS('xmi', 'type')
            except:
                pass
        else:
            elt.setAttributeNS('xmi', 'xmi:type', 'emof:PrimitiveType')


class Integer (DumpElement):

    def __init__(self, doc):
        super(Integer, self).__init__(doc)

    def process(self, obj, elt):
        super(Integer, self).process(obj, elt)
        elt.setAttributeNS('xmi', 'xmi:type', 'emof:Integer')
        #content = self._doc.createTextNode(unicode(obj))
        #elt.appendChild(content)



class Boolean (DumpElement):

    def __init__(self, doc):
        super(Boolean, self).__init__(doc)

    def process(self, obj, elt):
        super(Boolean, self).process(obj, elt)
        elt.setAttributeNS('xmi', 'xmi:type', 'emof:Boolean')
        #content = self._doc.createTextNode(unicode(obj))
        #elt.appendChild(content)



class String (DumpElement):

    def __init__(self, doc):
        super(String, self).__init__(doc)

    def process(self, obj, elt):
        super(String, self).process(obj, elt)
        elt.setAttributeNS('xmi', 'xmi:type', 'emof:String')
        #content = self._doc.createTextNode(unicode(obj))
        #elt.appendChild(content)

class UnlimitedNatural (DumpElement):

    def __init__(self, doc):
        super(UnlimitedNatural, self).__init__(doc)

    def process(self, obj, elt):
        super(UnlimitedNatural, self).process(obj, elt)
        elt.setAttributeNS('xmi', 'xmi:type', 'emof:UnlimitedNatural')
        #content = self._doc.createTextNode(unicode(obj))
        #elt.appendChild(content)

dumpers = {
    emof.core.Element: Element,
    emof.core.Tag: Tag,
    emof.core.Package: Package,
    emof.core.Comment: Comment,
    emof.core.EnumerationLiteral: EnumerationLiteral,
    emof.core.Class: Class,
    emof.core.Operation: Operation,
    emof.core.Parameter: Parameter,
    emof.core.Property: Property,
    emof.core.Enumeration: Enumeration,
    emof.core.PrimitiveType: PrimitiveType,
    emof.core.Integer: Integer,
    emof.core.Boolean: Boolean,
    emof.core.String: String,
    emof.core.UnlimitedNatural: UnlimitedNatural   
}

class Dumper (object):
    '''emof model dumper to an XMI file.'''

    def __init__(self):
        super(Dumper, self).__init__()
        self._doc = minidom.Document()
        root = self._doc.createElement('xmi:XMI')
        root.setAttribute('xmi:version', '2.1')
        root.setAttribute('xmlns:xmi', 'http://www.omg.org/XMI')
        root.setAttribute('xmlns:emof',
                          'http://schema.omg.org/spec/MOF/2.0/emof.xml')
        self._doc.appendChild(root)

    def dump(self, rep):
        for x in rep.Element:
            if x.isRoot:
                elt = Element(self._doc)(x, 'emof:Element')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Tag:
            if x.isRoot:
                elt = Tag(self._doc)(x, 'emof:Tag')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Package:
            if x.isRoot:
                elt = Package(self._doc)(x, 'emof:Package')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Comment:
            if x.isRoot:
                elt = Comment(self._doc)(x, 'emof:Comment')
                self._doc.documentElement.appendChild(elt)
        for x in rep.EnumerationLiteral:
            if x.isRoot:
                elt = EnumerationLiteral(self._doc)(x, 'emof:EnumerationLiteral')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Class:
            if x.isRoot:
                elt = Class(self._doc)(x, 'emof:Class')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Operation:
            if x.isRoot:
                elt = Operation(self._doc)(x, 'emof:Operation')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Parameter:
            if x.isRoot:
                elt = Parameter(self._doc)(x, 'emof:Parameter')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Property:
            if x.isRoot:
                elt = Property(self._doc)(x, 'emof:Property')
                self._doc.documentElement.appendChild(elt)
        for x in rep.Enumeration:
            if x.isRoot:
                elt = Enumeration(self._doc)(x, 'emof:Enumeration')
                self._doc.documentElement.appendChild(elt)
        for x in rep.PrimitiveType:
            if x.isRoot:
                elt = PrimitiveType(self._doc)(x, 'emof:PrimitiveType')
                self._doc.documentElement.appendChild(elt)
                
        return self._doc.toprettyxml()

# eof
